package com.androidgame.framework.impl;

import java.io.IOException;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;

import com.androidgame.framework.Music;

//stores a MediaPlayer instance along with a Prepared boolean
public class AndroidMusic implements Music, OnCompletionListener 
{
	//OnCompletionListener interface informs when a MediaPlayer 
	//has stopped playing back a music file
	
	MediaPlayer mediaPlayer;
	
	//used to tell when the MediaPlayer is prepared
	boolean isPrepared = false; 

	public AndroidMusic(AssetFileDescriptor assetDescriptor) 
	{
		
		//create and prepare the MediaPlayer
		mediaPlayer = new MediaPlayer();
		
		try 
		{
			//use AssetFileDescriptor for setup of media player
			mediaPlayer.setDataSource(assetDescriptor.getFileDescriptor(),
					assetDescriptor.getStartOffset(),
					assetDescriptor.getLength());
			
			//can only call MediaPlayer.start()/stop()/pause() when the
			//MediaPlayer is prepared
			mediaPlayer.prepare();
			isPrepared = true;
			
			mediaPlayer.setOnCompletionListener(this);
		} 
		
		catch (Exception e) 
		{
			throw new RuntimeException("Couldn't load music");
		}
	}
	
	public void dispose() 
	{
		//checks if the MediaPlayer is still playing
		if (mediaPlayer.isPlaying())
		{
			mediaPlayer.stop();
		}
		mediaPlayer.release();
	}
	
	public boolean isLooping() 
	{
		return mediaPlayer.isLooping();
	}
	
	public boolean isPlaying() 
	{
		return mediaPlayer.isPlaying();
	}

	public boolean isStopped() 
	{
		return !isPrepared;
	}
	
	public void play() 
	{
		//checks if the MediaPlayer is still playing
		if (mediaPlayer.isPlaying())
		{
			return;
		}
		
		try 
		{
			//done in a synchronized block, as we use the isPrepared flag, 
			//which might get set on a different thread
			synchronized (this) 
			{
				if (!isPrepared)
				{
					mediaPlayer.prepare();
				}
				
				mediaPlayer.start();
			}
		} 
		
		catch (IllegalStateException e) 
		{
			e.printStackTrace();
		} 
		
		catch (IOException e) 
		{
			e.printStackTrace();
		}
	}

	public void setLooping(boolean isLooping) 
	{
		mediaPlayer.setLooping(isLooping);
	}
	
	public void setVolume(float volume) 
	{
		mediaPlayer.setVolume(volume, volume);
	}
	
	//The setLooping() and setVolume() methods can be called in any state of the
	//MediaPlayer, and just delegate to the respective MediaPlayer methods.
	public void stop() 
	{
		mediaPlayer.stop();
		
		//done in a synchronized block, as we use the isPrepared flag, 
		//which might get set on a different thread
		synchronized (this) 
		{
			isPrepared = false;
		}
	}
	
	public void onCompletion(MediaPlayer player) 
	{
		//done in a synchronized block, as we use the isPrepared flag, 
		//which might get set on a different thread
		synchronized (this) 
		{
			isPrepared = false;
		}
	}
	
	public void pause() 
	{
		mediaPlayer.pause();
		
		//done in a synchronized block, as we use the isPrepared flag, 
		//which might get set on a different thread
		synchronized (this) 
		{
			isPrepared = false;
		}
	}
}
